#ifndef CONFIG_MODULES
	#include <linux/hdreg.h>
	#include <stdio.h>
	#include <unistd.h>
	#include <fcntl.h>
	#include <errno.h>
	#include <linux/types.h>
	#include <string.h>
	#include <sys/ioctl.h>

	#define pr_err  printf
	#define pr_info printf
	#define printk  printf
#endif

#define SCSI_DEV	"/dev/sda"

#define MAX_RAID_SERIAL_LEN 128
#ifdef CONFIG_MODULES
struct hd_driveid {
	unsigned short	config;		/* lots of obsolete bit flags */
	unsigned short	cyls;		/* Obsolete, "physical" cyls */
	unsigned short	reserved2;	/* reserved (word 2) */
	unsigned short	heads;		/* Obsolete, "physical" heads */
	unsigned short	track_bytes;	/* unformatted bytes per track */
	unsigned short	sector_bytes;	/* unformatted bytes per sector */
	unsigned short	sectors;	/* Obsolete, "physical" sectors per track */
	unsigned short	vendor0;	/* vendor unique */
	unsigned short	vendor1;	/* vendor unique */
	unsigned short	vendor2;	/* Retired vendor unique */
	unsigned char	serial_no[20];	/* 0 = not_specified */
	unsigned short	buf_type;	/* Retired */
	unsigned short	buf_size;	/* Retired, 512 byte increments
					 * 0 = not_specified
					 */
	unsigned short	ecc_bytes;	/* for r/w long cmds; 0 = not_specified */
	unsigned char	fw_rev[8];	/* 0 = not_specified */
	unsigned char	model[40];	/* 0 = not_specified */
	unsigned char	max_multsect;	/* 0=not_implemented */
	unsigned char	vendor3;	/* vendor unique */
	unsigned short	dword_io;	/* 0=not_implemented; 1=implemented */
	unsigned char	vendor4;	/* vendor unique */
	unsigned char	capability;	/* (upper byte of word 49)
					 *  3:	IORDYsup
					 *  2:	IORDYsw
					 *  1:	LBA
					 *  0:	DMA
					 */
	unsigned short	reserved50;	/* reserved (word 50) */
	unsigned char	vendor5;	/* Obsolete, vendor unique */
	unsigned char	tPIO;		/* Obsolete, 0=slow, 1=medium, 2=fast */
	unsigned char	vendor6;	/* Obsolete, vendor unique */
	unsigned char	tDMA;		/* Obsolete, 0=slow, 1=medium, 2=fast */
	unsigned short	field_valid;	/* (word 53)
					 *  2:	ultra_ok	word  88
					 *  1:	eide_ok		words 64-70
					 *  0:	cur_ok		words 54-58
					 */
	unsigned short	cur_cyls;	/* Obsolete, logical cylinders */
	unsigned short	cur_heads;	/* Obsolete, l heads */
	unsigned short	cur_sectors;	/* Obsolete, l sectors per track */
	unsigned short	cur_capacity0;	/* Obsolete, l total sectors on drive */
	unsigned short	cur_capacity1;	/* Obsolete, (2 words, misaligned int)     */
	unsigned char	multsect;	/* current multiple sector count */
	unsigned char	multsect_valid;	/* when (bit0==1) multsect is ok */
	unsigned int	lba_capacity;	/* Obsolete, total number of sectors */
	unsigned short	dma_1word;	/* Obsolete, single-word dma info */
	unsigned short	dma_mword;	/* multiple-word dma info */
	unsigned short  eide_pio_modes; /* bits 0:mode3 1:mode4 */
	unsigned short  eide_dma_min;	/* min mword dma cycle time (ns) */
	unsigned short  eide_dma_time;	/* recommended mword dma cycle time (ns) */
	unsigned short  eide_pio;       /* min cycle time (ns), no IORDY  */
	unsigned short  eide_pio_iordy; /* min cycle time (ns), with IORDY */
	unsigned short	words69_70[2];	/* reserved words 69-70
					 * future command overlap and queuing
					 */
	unsigned short	words71_74[4];	/* reserved words 71-74
					 * for IDENTIFY PACKET DEVICE command
					 */
	unsigned short  queue_depth;	/* (word 75)
					 * 15:5	reserved
					 *  4:0	Maximum queue depth -1
					 */
	unsigned short  words76_79[4];	/* reserved words 76-79 */
	unsigned short  major_rev_num;	/* (word 80) */
	unsigned short  minor_rev_num;	/* (word 81) */
	unsigned short  command_set_1;
	unsigned short  command_set_2;
	unsigned short  cfsse;
	unsigned short  cfs_enable_1;
	unsigned short  cfs_enable_2;
	unsigned short  csf_default;
	unsigned short  dma_ultra;	/* (word 88) */
	unsigned short	trseuc;		/* time required for security erase */
	unsigned short	trsEuc;		/* time required for enhanced erase */
	unsigned short	CurAPMvalues;	/* current APM values */
	unsigned short	mprc;		/* master password revision code */
	unsigned short	hw_config;
	unsigned short	acoustic;
	unsigned short	msrqs;		/* min stream request size */
	unsigned short	sxfert;		/* stream transfer time */
	unsigned short	sal;		/* stream access latency */
	unsigned int	spg;		/* stream performance granularity */
	unsigned long long lba_capacity_2;/* 48-bit total number of sectors */
	unsigned short	words104_125[22];/* reserved words 104-125 */
	unsigned short	last_lun;	/* (word 126) */
	unsigned short	word127;
	unsigned short	dlf;
	unsigned short  csfo;
	unsigned short	words130_155[26];/* reserved vendor words 130-155 */
	unsigned short	word156;	/* reserved vendor word 156 */
	unsigned short	words157_159[3];/* reserved vendor words 157-159 */
	unsigned short	cfa_power;
	unsigned short	words161_175[15];/* Reserved for CFA */
	unsigned short	words176_205[30];/* Current Media Serial Number */
	unsigned short	words206_254[49];/* reserved words 206-254 */
	unsigned short	integrity_word;
};
#endif

#ifdef CONFIG_MODULES
static struct file* vfs_open( const char *name )
{
	struct file *fp = filp_open( name , O_RDONLY, 0444 );
	if ( IS_ERR( fp ) ) {
		pr_err("filp_open file %s failed.\n", name );
		fp = NULL;
	}
	return fp;
}
#else
static FILE* vfs_open( const char *name )
{
	FILE *fp = fopen( name , "w+");
	if ( NULL == fp ) {
		pr_err("filp_open file %s failed.\n", name );
		fp = NULL;
	}
	return fp;
}
#endif

#ifdef CONFIG_MODULES
static int vfs_close( struct file *fp )
{
	return filp_close( fp, NULL );
}
#else
static int vfs_close( FILE *fp )
{
	return fclose( fp );
}
#endif

#ifdef CONFIG_MODULES
static long vfs_ioctl( struct file *filp, unsigned int cmd, unsigned long arg )
{
	int error = -ENOTTY;

	if ( !filp->f_op )
		goto out;
	if ( filp->f_op->unlocked_ioctl ) {
		error = filp->f_op->unlocked_ioctl( filp, cmd, arg );
		if ( error == -ENOIOCTLCMD )
			error = -EINVAL;
		goto out;
	}
out:
	return error;
}
#endif

/*
 * 取得scsi设备序列号
 * 通过SCSI INQUIRY命令取得Vital Product Data(VPD)页面信息
 * Page Code 80h - Unit serial number
 */
int scsi_get_inquiry( const char *name, char *buf )
{
	int ret;
	struct hd_driveid id;
#ifdef CONFIG_MODULES
	struct file *fp = NULL;
	mm_segment_t old_fs;

	fp = vfs_open( name );
	if ( NULL == fp ) {
		return -1;
	}

	old_fs = get_fs(); 	// 改变ioctl只能操作用户空间的限制
	set_fs( KERNEL_DS );
	ret = vfs_ioctl( fp, HDIO_GET_IDENTITY, ( unsigned long )&id );
	if ( ret < 0 ) {
		set_fs( old_fs );
		pr_err("vfs_ioctl %s SG_IO failed./n", name );
		goto _out;
	}
	set_fs( old_fs );

	strncpy(buf, id.serial_no, 128);
_out:
	vfs_close( fp );
	return ret;
#else
	int fd = open(name , O_RDONLY);
	ret = ioctl( fd, HDIO_GET_IDENTITY, ( unsigned long )&id );
	if ( ret < 0 ) {
		pr_err("vfs_ioctl %s SG_IO failed.\n", name );
		goto _out;
	}

	strncpy(buf, id.serial_no, 128);
_out:
	close( fd );
	return ret;
#endif
}

static int getid(void *unused)
{
	char hdd_sn[MAX_RAID_SERIAL_LEN];	// 磁盘序列号
	int ret, i, len, len_2;

#ifdef CONFIG_MODULES
	struct file *fp = NULL;
	mm_segment_t fs;	loff_t pos;
	set_current_state(TASK_UNINTERRUPTIBLE);//设置当前线程不可打断
#else
	FILE *fp = NULL;
#endif

	memset(hdd_sn, 0, MAX_RAID_SERIAL_LEN);

	/**************获取磁盘序列值*********************/
	ret = scsi_get_inquiry( SCSI_DEV, hdd_sn );
	if(!ret){
		/***********打印硬盘ID号*********/
		pr_info("scsi_get_inquiry: %s\n", hdd_sn);
	}else{
		pr_err("scsi_get_inquiry error: %d\n", ret);
		goto _out;
	}
	return 0;

_out:
	return ret;
}

#ifndef CONFIG_MODULES
void main(){
	getid(NULL);
}
#endif